//@version=5
indicator("Combined PhantomFlow and Follow Line", "Combined PF & FL", true, max_lines_count = 500)

// New settings
colorIntensityThreshold = input.float(1.5, "Color Intensity Threshold", minval=1.0, maxval=3.0, step=0.1)
BBperiod = input.int(21, "BB Period", minval=1)
BBdeviations = input.float(1.00, "BB Deviations", minval=0.1, step=0.1)
UseATRfilter = input.bool(true, "Use ATR Filter")
ATRperiod = input.int(5, "ATR Period", minval=1)

// PhantomFlow Trend Detector variables and functions
type fractal
    int fractal_bar
    box bx

type wave
    bool isActive
    bool isSearchCountertrendFormation
    bool isSearchTrendFormation
    int bar_start
    int bar_end
    float high_price
    float low_price
    array<line> lines

var array<wave> waves_down = array.new<wave>()
var array<wave> waves_up = array.new<wave>()
var array<int> fractals_down_zigzag = array.new<int>()
var array<int> fractals_up_zigzag = array.new<int>()
var array<bool> listFractals = array.new<bool>()
var array<fractal> LevelsShort = array.new<fractal>()
var array<fractal> LevelsLong = array.new<fractal>()
var array<fractal> LevelsShortHTF = array.new<fractal>()
var array<fractal> LevelsLongHTF = array.new<fractal>()
var array<int> levelsToCoef = array.new<int>()

ltf = timeframe.period
up_trend_start = color.rgb(255, 253, 106)
up_trend_end = color.rgb(0, 255, 0)
down_trend_start = color.rgb(255, 89, 255)
down_trend_end = color.rgb(255, 0, 0)
n_zigzag = 2

is_down_fractal_zigzag() =>
    bool isConfirmFractal = false
    for i = 0 to n_zigzag + n_zigzag
        if low[n_zigzag] > low[i]
            break
        if (i == n_zigzag + n_zigzag)
            isConfirmFractal := true
    isConfirmFractal

is_up_fractal_zigzag() =>
    bool isConfirmFractal = false
    for i = 0 to n_zigzag + n_zigzag
        if high[n_zigzag] < high[i]
            break
        if (i == n_zigzag + n_zigzag)
            isConfirmFractal := true
    isConfirmFractal

check_is_add_up_liquidity() =>
    if array.size(fractals_up_zigzag) > 2
        item1 = array.last(fractals_up_zigzag)
        item2 = array.get(fractals_up_zigzag, array.size(fractals_up_zigzag) - 2)
        item3 = array.get(fractals_up_zigzag, array.size(fractals_up_zigzag) - 3)
        if (high[bar_index - item1] < high[bar_index - item2] and high[bar_index - item2] < high[bar_index - item3])
            if array.size(waves_up) == 0
                array.push(waves_up, wave.new(true, true, true, item3, item1, high[bar_index - item3], high[bar_index - item1], array.new<line>()))
                true
            else
                wave last_wave = array.last(waves_up)
                if (item3 >= last_wave.bar_start and item3 < last_wave.bar_end)
                    last_wave.bar_end := item1
                    last_wave.low_price := high[bar_index - item1]
                    last_wave.isActive := false
                    true
                else
                    array.push(waves_up, wave.new(true, true, true, item3, item1, high[bar_index - item3], high[bar_index - item1], array.new<line>()))
                    true

check_is_add_down_liquidity() =>
    if array.size(fractals_down_zigzag) > 2
        item1 = array.last(fractals_down_zigzag)
        item2 = array.get(fractals_down_zigzag, array.size(fractals_down_zigzag) - 2)
        item3 = array.get(fractals_down_zigzag, array.size(fractals_down_zigzag) - 3)
        if (low[bar_index - item1] > low[bar_index - item2] and low[bar_index - item2] > low[bar_index - item3])
            if array.size(waves_down) == 0
                array.push(waves_down, wave.new(true, true, true, item3, item1, low[bar_index - item1], low[bar_index - item3], array.new<line>()))
                true
            else
                wave last_wave = array.last(waves_down)
                if (item3 >= last_wave.bar_start and item3 < last_wave.bar_end)
                    last_wave.bar_end := item1
                    last_wave.high_price := low[bar_index - item1]
                    last_wave.isActive := false
                    true
                else
                    array.push(waves_down, wave.new(true, true, true, item3, item1, low[bar_index - item1], low[bar_index - item3], array.new<line>()))
                    true

bool is_search_fractal_zigzag = bar_index - n_zigzag * 2 >= 0
if is_search_fractal_zigzag
    if is_up_fractal_zigzag()
        if array.size(fractals_up_zigzag) == 0
            array.push(fractals_up_zigzag, bar_index - (n_zigzag))
            array.push(listFractals, true)
        else
            isUpLastFractal = array.last(listFractals)
            lastFractal = array.last(fractals_up_zigzag)
            if isUpLastFractal and high[bar_index - lastFractal] < high[n_zigzag]
                array.pop(fractals_up_zigzag)
                array.push(fractals_up_zigzag, bar_index - (n_zigzag))
                check_is_add_up_liquidity()
            if not isUpLastFractal
                lastFractalDown = array.last(fractals_down_zigzag)
                if (low[bar_index - lastFractalDown] < high[n_zigzag])
                    array.push(fractals_up_zigzag, bar_index - (n_zigzag))
                    array.push(listFractals, true)
                    check_is_add_up_liquidity()
    if is_down_fractal_zigzag()
        if array.size(fractals_down_zigzag) == 0
            array.push(fractals_down_zigzag, bar_index - (n_zigzag))
            array.push(listFractals, false)
        else
            isUpLastFractal = array.last(listFractals)
            lastFractal = array.last(fractals_down_zigzag)
            if not isUpLastFractal and low[bar_index - lastFractal] > low[n_zigzag]
                array.pop(fractals_down_zigzag)
                array.push(fractals_down_zigzag, bar_index - (n_zigzag))
                check_is_add_down_liquidity()
            if isUpLastFractal
                lastFractalUp = array.last(fractals_up_zigzag)
                if (high[bar_index - lastFractalUp] > low[n_zigzag])
                    array.push(fractals_down_zigzag, bar_index - (n_zigzag))
                    array.push(listFractals, false)
                    check_is_add_down_liquidity()

bool isDownTrend = false
bool isUpTrend = false
var float last_low = na
var float last_high = na

if (array.size(waves_up) != 0 and array.size(waves_down) != 0)
    wave lastWaveUp = array.last(waves_up)
    wave lastWaveDown = array.last(waves_down)
    if (close < lastWaveDown.high_price and close > lastWaveUp.low_price)
        if (lastWaveDown.bar_end < lastWaveUp.bar_end)
            isUpTrend := true
            last_low := lastWaveUp.low_price
            last_high := lastWaveUp.high_price
        else
            isDownTrend := true
            last_low := lastWaveDown.low_price
            last_high := lastWaveDown.high_price
    if (close >= lastWaveDown.high_price and close > lastWaveUp.low_price)
        isUpTrend := true
        last_low := lastWaveUp.low_price
        last_high := lastWaveUp.high_price
    if (close < lastWaveDown.high_price and close <= lastWaveUp.low_price)
        isDownTrend := true
        last_low := lastWaveDown.low_price
        last_high := lastWaveDown.high_price

if (array.size(waves_up) != 0 and array.size(waves_down) == 0)
    wave lastWave = array.last(waves_up)
    if (close > lastWave.low_price)
        isUpTrend := true
        last_low := lastWave.low_price
        last_high := lastWave.high_price

if (array.size(waves_down) != 0 and array.size(waves_up) == 0)
    wave lastWave = array.last(waves_down)
    if (close < lastWave.high_price)
        isDownTrend := true
        last_low := lastWave.low_price
        last_high := lastWave.high_price

var color trend_css = na
float signal = ta.ema(close, 1)
color signalColorDown = color.from_gradient(signal, last_low, last_high, up_trend_start, up_trend_end)
color signalColorUp = color.from_gradient(signal, last_low, last_high, down_trend_end, down_trend_start)

if isDownTrend
    trend_css := signalColorUp
if isUpTrend
    trend_css := signalColorDown

// Follow Line Indicator variables and calculations
BBUpper = ta.sma(close, BBperiod) + ta.stdev(close, BBperiod) * BBdeviations
BBLower = ta.sma(close, BBperiod) - ta.stdev(close, BBperiod) * BBdeviations

var float TrendLine = 0.0
var int iTrend = 0
var float buy = 0.0
var float sell = 0.0

BBSignal = close > BBUpper ? 1 : close < BBLower ? -1 : 0

// Calculate ATR outside of the if statements for consistency
float atrValue = ta.atr(ATRperiod)

if BBSignal == 1 and UseATRfilter
    TrendLine := low - atrValue
    if TrendLine < TrendLine[1]
        TrendLine := TrendLine[1]

if BBSignal == -1 and UseATRfilter
    TrendLine := high + atrValue
    if TrendLine > TrendLine[1]
        TrendLine := TrendLine[1]

if BBSignal == 0 and UseATRfilter
    TrendLine := TrendLine[1]

if BBSignal == 1 and not UseATRfilter
    TrendLine := low
    if TrendLine < TrendLine[1]
        TrendLine := TrendLine[1]

if BBSignal == -1 and not UseATRfilter
    TrendLine := high
    if TrendLine > TrendLine[1]
        TrendLine := TrendLine[1]

if BBSignal == 0 and not UseATRfilter
    TrendLine := TrendLine[1]

iTrend := iTrend[1]
if TrendLine > TrendLine[1]
    iTrend := 1
if TrendLine < TrendLine[1]
    iTrend := -1

buy := iTrend[1] == -1 and iTrend == 1 ? 1 : na
sell := iTrend[1] == 1 and iTrend == -1 ? 1 : na

// Plot candles
plotcandle(open, high, low, close, color = trend_css, wickcolor = trend_css, bordercolor = trend_css)

// Plot trend line
plot(TrendLine, color = iTrend > 0 ? color.blue : color.red, style = plot.style_line, linewidth = 2, title = "Trend Line")

// Functions to check color intensity with adjustable threshold
is_green_enough(c) =>
    green = color.g(c)
    red = color.r(c)
    blue = color.b(c)
    green > 200 and green > red * colorIntensityThreshold and green > blue * colorIntensityThreshold

is_red_enough(c) =>
    red = color.r(c)
    green = color.g(c)
    blue = color.b(c)
    red > 200 and red > green * colorIntensityThreshold and red > blue * colorIntensityThreshold

// Updated Signal conditions
longCondition = iTrend > 0 and low > TrendLine and close > high[1] and is_green_enough(trend_css)
shortCondition = iTrend < 0 and high < TrendLine and close < low[1] and is_red_enough(trend_css)

// Plotting signals only if color conditions are met
plotshape(longCondition, style = shape.triangleup, location = location.belowbar, color = color.green, size = size.small, title = "Long Signal")
plotshape(shortCondition, style = shape.triangledown, location = location.abovebar, color = color.red, size = size.small, title = "Short Signal")




